use std::fs;
use std::fs::{DirBuilder, File, read_dir};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};


/**
    啥?!你问我为什么不用静态变量
	
	因为它报错~ 因为我驾驭不了~

	二就是直接用PathBuf也挺爽的
 */
fn 分片_root_path<P: AsRef<Path>>( path: P)-> PathBuf {
	Path::new("./public/分片").join(path)
}


/**
	id: 由 文件名 + md5 组成
*/
pub trait 分片 {
	
	/**
	#推入一个分片
	 */
	fn push_data(&self,piece_number:usize,piece_data:&[u8]);

	/**
	#合成文件
	
	**return** : [`None`]:合成失败 , [`Some`] (文件,总分片数)
	 */
	fn make_file(&self)->Option<(File,usize)>;
	/**
	#删除所有分片
	 */
	fn delete_all_piece(self);
}

/**
    建立以 id 命名的目录

	分片文件名从 1 开始

	0 文件名是最后合成的文件名
 */
pub struct 分片操作器(String);

impl 分片操作器{
	pub fn path(&self) -> PathBuf {
		分片_root_path(&self.0)
	}
	fn create_piece(id:&String,piece_number:usize,data:&[u8]){
		let path_buf = 分片_root_path(id);
		// DirBuilder::new().create(path_buf.as_path());//由分片构造器创建目录
		let mut piece_file =
			File::create(path_buf.join(piece_number.to_string()))
				.unwrap();//上面必然存在目录,所以这个不用担心啦
		piece_file.write(data);
	}
	fn make_file(id:&String) -> Option<(File,usize)>{//( 合成后的文件 , 总分片数 )
		let path = 分片_root_path(id);
		let mut list:Vec<usize> = Vec::new();
		if let Ok(v) = read_dir(&path) {
			for v in v {
				if let Ok(v) = v {
					let file_name = v.file_name().into_string().unwrap();
					let i = file_name.parse::<usize>().unwrap();
					if i!=0{
						(&mut list).push(i);
					}
				}
			}
		}else { //Err
			return None;
		}
		list.sort();
		// println!("{:?}",&list);
		let mut file = File::create(&path.join("0"))
			.unwrap();//上面有检查,所以不用担心这个啦
		let mut buf = [0_u8;1024];
		for v in &list {
			let mut f = File::open(&path.join(v.to_string()))
				.unwrap();//由上面找到的,所以必然存在,不用担心啦~
			while let Ok(v) = f.read(&mut buf){
				if v==0 {break;}
				(&mut file).write(&buf[0..v]);
			};
		}
		Some((file,list.len()))
	}
	fn delete_all_piece(id:&String){
		fs::remove_dir_all(分片_root_path(id));
	}
}

impl 分片 for 分片操作器 {
	fn push_data(&self, piece_number: usize, piece_data: &[u8]) {
		分片操作器::create_piece(&self.0,piece_number,piece_data)
	}
	
	fn make_file(&self) -> Option<(File, usize)> {
		分片操作器::make_file(&self.0)
	}
	
	fn delete_all_piece(self) {
		分片操作器::delete_all_piece(&self.0);
	}
}


///构建一个 [`分片操作器`]
pub struct 分片构造器;

impl 分片构造器 {
	pub fn new(id:String) -> 分片操作器 {
		DirBuilder::new().create(分片_root_path(&id));
		分片操作器(id)
	}
}




//--mod--//